"""
MQTT客户端实现
"""
import ssl
import time
from typing import List

import paho.mqtt.client as mqtt

from common.config import settings
from common.database import DatabaseManager
from common.logger import create_logger
from mqtt.consumer.mqtt_handlers import HandlerFactory


class MQTTClient:
	def __init__(self):
		"""
		MQTT客户端初始化
		"""
		self.logger = create_logger("mqtt", settings.log_level, settings.log_file)

		# 初始化数据库连接
		self.db = DatabaseManager(
			host=settings.db_host,
			port=settings.db_port,
			user=settings.db_user,
			password=settings.db_password,
			database=settings.db_name
		)
		self.logger.info(f"数据库连接初始化: {settings.db_host}:{settings.db_port}/{settings.db_name}")

		# 创建MQTT客户端
		self.client = mqtt.Client(
			client_id=f"sensor_data_consumer_{int(time.time())}",
			clean_session=False
		)

		# 设置回调
		self.client.on_connect = self._on_connect
		self.client.on_message = self._on_message
		self.client.on_disconnect = self._on_disconnect
		self.client.on_subscribe = self._on_subscribe

		# 认证设置
		if settings.mqtt_user and settings.mqtt_password:
			self.client.username_pw_set(settings.mqtt_user, settings.mqtt_password)

		# TLS设置
		if settings.mqtt_ca_cert:
			try:
				self.client.tls_set(
					ca_certs=settings.mqtt_ca_cert,
					cert_reqs=ssl.CERT_NONE  # 跳过证书验证
				)
				self.client.tls_insecure_set(True)
				self.logger.info("TLS configured with certificate")
			except Exception as e:
				self.logger.error(f"Failed to configure TLS: {str(e)}")
				# 如果证书配置失败，尝试不使用证书
				self.client.tls_set(cert_reqs=ssl.CERT_NONE)
				self.client.tls_insecure_set(True)
		else:
			# 如果没有提供证书，仍然使用TLS但不验证
			self.client.tls_set(cert_reqs=ssl.CERT_NONE)
			self.client.tls_insecure_set(True)
			self.logger.warning("Using TLS without certificate verification")

		# 连接状态
		self.connected = False
		self.reconnect_attempts = 0
		self.subscribed_topics: List[str] = []

	def _on_connect(self, client, userdata, flags, rc):
		"""连接回调"""
		if rc == 0:
			self.connected = True
			self.reconnect_attempts = 0
			self.logger.info(f"成功连接到MQTT代理: {settings.mqtt_broker}:{settings.mqtt_port}")

			# 订阅topic（从配置文件读取）
			# Worker节点 (.env.test): /meter/+/telemetry
			# Worker-Show节点 (.env.show): /meter/+/telemetry/qz
			topic = settings.mqtt_subscribe_topic
			client.subscribe(topic, qos=1)  # QoS 1确保至少一次交付
			self.subscribed_topics.append(topic)
			self.logger.info(f"已订阅主题: {topic}")
		else:
			error_messages = {
				1: "连接拒绝 - 协议版本不正确",
				2: "连接拒绝 - 客户端标识符无效",
				3: "连接拒绝 - 服务器不可用",
				4: "连接拒绝 - 用户名或密码错误",
				5: "连接拒绝 - 未授权"
			}
			error_msg = error_messages.get(rc, f"未知错误代码: {rc}")
			self.logger.error(f"连接失败: {error_msg}")
			self.connected = False

	def _on_subscribe(self, client, userdata, mid, granted_qos):
		"""订阅回调"""
		self.logger.debug(f"订阅确认, MID: {mid}, QoS: {granted_qos}")

	def _on_message(self, client, userdata, msg):
		"""消息回调"""
		try:
			# 脱敏，只打印长度与 topic
			self.logger.debug("Recv topic=%s payload_len=%d", msg.topic, len(msg.payload))
			
			# 容错解码，处理硬件端可能发送非 UTF-8 编码的数据
			try:
				payload_str = msg.payload.decode('utf-8')
			except UnicodeDecodeError:
				# 尝试其他常见编码
				try:
					payload_str = msg.payload.decode('gbk')
					self.logger.warning("topic=%s 使用 GBK 编码解码成功", msg.topic)
				except UnicodeDecodeError:
					# 如果仍然失败，使用 latin-1 容错解码（不会报错）
					payload_str = msg.payload.decode('latin-1')
					self.logger.warning("topic=%s 使用 latin-1 容错解码，原始数据可能有误", msg.topic)
					# 记录原始字节以便调试
					self.logger.debug("topic=%s 原始字节: %s", msg.topic, msg.payload.hex())
			
			handler = HandlerFactory.get_handler(msg.topic, self.db)
			handler.handle(msg.topic, payload_str)
		except Exception as e:
			self.logger.error("消息处理异常: %s", e, exc_info=True)

	def _on_disconnect(self, client, userdata, rc):
		"""断开连接回调"""
		self.connected = False
		if rc != 0:
			self.logger.warning(f"意外断开连接 (代码: {rc})")
		else:
			self.logger.info("正常断开连接")

	def connect(self):
		"""连接MQTT代理并启动循环"""
		try:
			self.logger.info(f"尝试连接到 {settings.mqtt_broker}:{settings.mqtt_port}")
			self.client.connect(
				settings.mqtt_broker,
				settings.mqtt_port,
				60  # 保持连接时间
			)
			self.client.loop_start()

			# 等待连接建立
			for i in range(10):  # 最多等待5秒
				if self.connected:
					self.logger.info("连接成功建立")
					return True
				time.sleep(0.5)

			self.logger.error("连接超时")
			return False
		except Exception as e:
			self.logger.error(f"连接错误: {str(e)}")
			return False

	def disconnect(self):
		"""断开连接并清理资源"""
		self.logger.info("正在断开连接并清理资源...")
		if self.connected:
			self.client.loop_stop()
			self.client.disconnect()
			self.logger.info("已断开与MQTT代理的连接")
		
		# 关闭数据库连接
		if self.db and self.db.connection:
			self.db.connection.close()
			self.logger.info("数据库连接已关闭")

	def run(self):
		"""运行客户端（含重连机制）"""
		self.logger.info("启动MQTT客户端...")

		while True:
			try:
				if not self.connected:
					if self.reconnect_attempts < settings.max_reconnect_attempts:
						self.logger.info(
							f"尝试连接 ({self.reconnect_attempts + 1}/{settings.max_reconnect_attempts})...")
						if self.connect():
							self.logger.info("连接已建立")
							self.reconnect_attempts = 0
						else:
							self.reconnect_attempts += 1
							delay = min(
								settings.reconnect_delay * self.reconnect_attempts,
								300  # 最大延迟5分钟
							)
							self.logger.warning(
								f"连接失败。将在 {delay} 秒后重试..."
							)
							time.sleep(delay)
					else:
						self.logger.error("已达到最大重连尝试次数。退出程序。")
						break
				else:
					# 保持连接，定期检查连接状态
					time.sleep(5)

			except KeyboardInterrupt:
				self.logger.info("收到中断信号，正在关闭...")
				break
			except Exception as e:
				self.logger.error(f"运行过程中发生未预期错误: {str(e)}")
				time.sleep(10)  # 发生错误时等待一段时间再继续
